local zklua = require "zklua"
local config = require "config"
local cjson = require "cjson"
local service_model = require "model.module"
local server_model = require "model.server"
local domain_model = require "model.domain"
local _M = {}
local zk = {}
local server_init_timer

local string_split = function(szFullString, szSeparator)
    local nFindStartIndex = 1
    local nSplitIndex = 1
    local nSplitArray = {}
    while true do
        local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex)
        if not nFindLastIndex then
            nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
            break
        end
        nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1)
        nFindStartIndex = nFindLastIndex + string.len(szSeparator)
        nSplitIndex = nSplitIndex + 1
    end
    return nSplitArray
end

local getDomainId = function(domains, domain_name)
    -- 循环domain
    for _, domain in pairs(domains) do
        if domain["domain_name"] == domain_name then
            return domain["id"]
        end
    end
    return nil
end

local getServiceId = function(services, service_name)
    for _, service in pairs(services) do
        if service["name"] == service_name then
            return service["id"]
        end
    end
    return nil
end

local handleServer = function(serviceId, servers, host, port)
    port = tonumber(port)
    if table.getn(servers) == 0 then
        server_model.add(serviceId, host, port, 1, 'zk created', 'http://')
    else
        for _, server in pairs(servers) do
            if server["ip"] == host and server["port"] == port then
               return
            end
        end
        server_model.add(serviceId, host, port, 1, 'zk created', 'http://')
    end

end

local init_server = function()
    local path = config["zklua_watch_path"]
    local ret,children_data = zklua.get_children(zk, path, 1)
    ngx.log(ngx.INFO,'query zk  children_data path:', path, ',ret:' ,ret)
    if ret == 0 then
        local domains, _  = domain_model.getDomainsNotEmpty()
        for _,s in pairs(children_data) do
            local nsa = string_split(s, '&')
            if table.getn(nsa) == 4 then
                local domainId = getDomainId(domains, nsa[1])
                if domainId ~= nil then
                    local services, _ = service_model.getServices(domainId)
                    local  serviceId = getServiceId(services, nsa[2])
                    if serviceId ~= nil then
                        local servers = server_model.getServiceServers(serviceId, 1)
                        handleServer(serviceId, servers, nsa[3], nsa[4])
                    end
                end
            end
        end
    end
end

server_init_timer = function(premature)
    if not premature then
        local ret, result = pcall(init_server)
        if ret then
            ngx.log(ngx.INFO, "server_init_timer over")
        else
            ngx.log(ngx.ERR, "error server_init_timer:", result)
        end
        ngx.timer.at(15, server_init_timer)
    end
end

local zklua_my_watcher = function(udata, type, state, path)
    ngx.log(ngx.INFO, '================================================================================zklua_my_watcher', type, state, path)
    if type == 4 and state == 3 then
       --_M.init_server()
    end

    if type == zklua.ZOO_SESSION_EVENT then
        if state == zklua.ZOO_CONNECTED_STATE then
            ngx.log(ngx.INFO,"Connected to zookeeper service successfully!");
        elseif (state == ZOO_EXPIRED_SESSION_STATE) then
            ngx.log(ngx.INFO,"Zookeeper session expired!");
        end
    end
end

_M.init = function()
    --zklua.set_log_stream(config["zklua_log"])
    ngx.log(ngx.INFO,'.............zookeeper start init............')
    zk = zklua.init(config["zklua_host"], zklua_my_watcher, 10000)

    --ngx.log(ngx.INFO,'errors=', zklua.ZAPIERROR)
    --ngx.log(ngx.INFO,'errors=', zklua.ZNONODE)
    --ngx.log(ngx.INFO,'errors=', zklua.ZNOAUTH)
    --ngx.log(ngx.INFO,'errors=', zklua.ZBADVERSION)
    --ngx.log(ngx.INFO,'errors=', zklua.ZNOCHILDRENFOREPHEMERALS)
    --ngx.log(ngx.INFO,'errors=', zklua.ZNODEEXISTS)
    --ngx.log(ngx.INFO,'errors=', zklua.ZNOTEMPTY)
    --ngx.log(ngx.INFO,'errors=', zklua.ZSESSIONEXPIRED)
    --ngx.log(ngx.INFO,'errors=', zklua.ZINVALIDCALLBACK)
    --ngx.log(ngx.INFO,'errors=', zklua.ZINVALIDACL)
    --ngx.log(ngx.INFO,'errors=', zklua.ZAUTHFAILED)
    --ngx.log(ngx.INFO,'errors=', zklua.ZCLOSING)
    --ngx.log(ngx.INFO,'errors=', zklua.ZNOTHING)
    --ngx.log(ngx.INFO,'errors=', zklua.ZSESSIONMOVED)

    local zklua_watch_path = config["zklua_watch_path"]

    local ret, sta = zklua.exists(zk, zklua_watch_path, 0)
    ngx.log(ngx.INFO,'exists',ret)
    if ret ~= 0 then
        local acl = '[{"perms":' .. zklua.ZOO_PERM_ALL .. ',"scheme":"world","id":"anyone"}]'
        local ret1, sta1 = zklua.create(zk, zklua_watch_path, '', cjson.decode(acl), 0)
        if ret1 == 0 then
            ngx.log(ngx.INFO,'create zk node success')
        end
    end

    local ok, err = ngx.timer.at(15, server_init_timer)
    if not ok then
        ngx.log(ngx.ERR, "failed to create server_init_timer: ", err)
        return
    end
    ngx.log(ngx.INFO,'.............zookeeper end init............')
end

return _M